/**
 * Copyright 2010-2012 David L. McCloskey
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package net.akwire.twitter2blogger;

import com.google.gdata.client.blogger.BloggerService;
import com.google.gdata.data.Entry;
import com.google.gdata.data.Feed;
import com.google.gdata.data.Person;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import winterwell.jtwitter.Twitter;
import winterwell.jtwitter.Twitter.Status;

/**
 * A Command line argument class which takes the day's tweets from a specified
 * twitter account and posts them to a specified blog on a specified user's
 * Blogger account.
 *
 * @author David L. McCloskey
 *
 */
public class Twitter2Blogger {

  private static final String METAFEED_URL =
          "http://www.blogger.com/feeds/default/blogs";
  private static final String FEED_URI_BASE = "http://www.blogger.com/feeds";
  private static final String POSTS_FEED_URI_SUFFIX = "/posts/default";
  private static final String POST_TITLE = "A Day's Worth of Twitter";
  private static final String POST_AUTHOR = "twitter2blogger";
  String feedUri;
  String twitterUsername;
  String bloggerUsername;
  String bloggerPassword;
  String blogName;
  boolean makeDraft;

  /**
   * The main method invoked by the command line.
   *
   * @param args no arguments are taken
   */
  public static void main(String[] args) {
    /*
     * Enter your information in the following 4 variables. TODO: Read from
     * command line or configuration file
     */
    String twitterUsername = "";
    String bloggerUsername = "";
    String bloggerPassword = "";
    String blogName = "";
    boolean makeDraft = true;

    /*
     * Begin processing.
     */
    Twitter2Blogger t2b = new Twitter2Blogger(twitterUsername,
            bloggerUsername, bloggerPassword, blogName, makeDraft);
    List<String> tweets = t2b.getTodaysTweetStringsWithTimes();
    if (tweets.isEmpty() || tweets == null) {
      System.out.println("No tweets to post... exiting.");
      System.exit(0);
    }
    String body = t2b.makeBody(tweets);

    System.out.println(body);
    t2b.postToBlog(blogName, body);
  }

  private Twitter2Blogger(String twitterUsername, String bloggerUsername,
          String bloggerPassword, String blogName, boolean makeDraft) {
    this.twitterUsername = twitterUsername;
    this.bloggerUsername = bloggerUsername;
    this.bloggerPassword = bloggerPassword;
    this.blogName = blogName;
    this.makeDraft = makeDraft;
  }

  private String makeBody(List<String> argTweets) {
    StringBuilder sb = new StringBuilder();
    List<String> tweets = new ArrayList<String>(argTweets);
    Collections.reverse(tweets);
    for (String s : tweets) {
      sb.append(twitterLinkify(s));
      sb.append("<br/>\n");
    }
    sb.append("<br/>");
    sb.append("You can find me as <a href=\"http://twitter.com/");
    sb.append(twitterUsername);
    sb.append("\">@");
    sb.append(twitterUsername);
    sb.append("</a> on Twitter.<br/>");
    return sb.toString();
  }

  private void postToBlog(String blogName, String body) {
    try {
      System.out.println("Posting a post with the following body to "
              + blogName);
      System.out.println(body);

      BloggerService service = new BloggerService("twitter2blogger");
      service.setUserCredentials(bloggerUsername, bloggerPassword);
      String blogId = getBlogId(blogName, service);
      feedUri = FEED_URI_BASE + "/" + blogId;
      createPost(service, POST_TITLE, body, POST_AUTHOR, bloggerUsername,
              false);
    } catch (final Exception e) {
      throw new Error("Error posting to blog.", e);
    }

  }

  private String twitterLinkify(String s) {
    String linkifiedString = replaceUrlsWithAnchors(s);
    linkifiedString = replaceTwitterIdWithLinkToProfile(linkifiedString);
    linkifiedString = replaceTwitterHashWithLinkToHashSearch(linkifiedString);
    return linkifiedString;
  }

  private String replaceUrlsWithAnchors(String s) {
    String[] words = s.split("\\s");
    StringBuilder linkifiedString = new StringBuilder();
    // Attempt to convert each item into an URL.
    for (String word : words) {
      try {
        URL url = new URL(word);
        // If possible then replace with anchor...
        linkifiedString.append("<a href=\"");
        linkifiedString.append(url);
        linkifiedString.append("\" rel=\"nofollow\">");
        linkifiedString.append(url);
        linkifiedString.append("</a> ");
      } catch (MalformedURLException e) {
        // If there was an URL that was not it!...
        linkifiedString.append(word);
        linkifiedString.append(' ');
      }
    }
    return linkifiedString.toString();
  }

  private String replaceTwitterIdWithLinkToProfile(String s) {
    return s.replaceAll("(\\s)@([a-zA-Z0-9_]*)",
            "$1<a href=\"http://twitter.com/"
            + "$2\" title=\"$2 profile on Twitter\" rel=\"nofollow\">@$2</a>");
  }

  private String replaceTwitterHashWithLinkToHashSearch(String s) {
    return s.replaceAll("(\\s)#([a-zA-Z0-9_]*)",
            "$1<a href=\"http://search.twitter"
            + ".com/search?q=%23$2\" title=\"search for $2 on Twitter\" "
            + "rel=\"nofollow\">#$2</a>");
  }

  private static String getBlogId(String blogName, BloggerService service)
          throws MalformedURLException, IOException, ServiceException, Error {
    String blogId = null;
    // Request the feed
    final URL feedUrl = new URL(METAFEED_URL);
    Feed resultFeed = service.getFeed(feedUrl, Feed.class);

    // Print the results
    System.out.println(resultFeed.getTitle().getPlainText());
    for (int i = 0; i < resultFeed.getEntries().size(); i++) {
      Entry entry = resultFeed.getEntries().get(i);
      String thisBlogName = entry.getTitle().getPlainText();
      System.out.println("\t" + thisBlogName);
      if (blogName.equals(thisBlogName)) {
        System.out.println(" Match");
        blogId = entry.getId().split("blog-")[1];
        System.out.println(" blog id: " + blogId);
      }
    }
    if (blogId == null) {
      throw new Error("User does not have blog named " + blogName);
    }
    return blogId;
  }

  public Entry createPost(BloggerService myService, String title,
          String content, String authorName, String userName, Boolean isDraft)
          throws ServiceException, IOException {
    // Create the entry to insert
    Entry myEntry = new Entry();
    myEntry.setTitle(new PlainTextConstruct(title));
    myEntry.setContent(new PlainTextConstruct(content));
    Person author = new Person(authorName, null, userName);
    myEntry.getAuthors().add(author);
    myEntry.setDraft(isDraft);

    // Ask the service to insert the new entry
    URL postUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
    return myService.insert(postUrl, myEntry);
  }

  private List<String> getTodaysTweetStringsWithTimes() {
    Twitter t = new Twitter();
    List<Status> statuses = t.getUserTimeline(twitterUsername);
    List<String> l = new ArrayList<String>();
    Date now = new Date();
    Calendar nowCal = Calendar.getInstance();
    nowCal.setTime(now);
    Calendar tweetCal = Calendar.getInstance();
    for (Status s : statuses) {
      tweetCal.setTime(s.createdAt);

      boolean tweetIsFromToday = (nowCal.get(Calendar.DAY_OF_YEAR) == tweetCal.
              get(Calendar.DAY_OF_YEAR) && nowCal.get(Calendar.YEAR)
              == tweetCal.get(Calendar.YEAR));
      if (tweetIsFromToday) {
        DateFormat df = new SimpleDateFormat("hh:mm:ss a");
        StringBuilder sb = new StringBuilder();
        sb.append(df.format(s.createdAt));
        sb.append(" - ");
        sb.append(s.toString());
        l.add(sb.toString());
      }

    }
    return l;
  }
}
